#ifndef     __RF_TASK_H
#define     __RF_TASK_H

#include "../rtos/thread.h"
#include "../utils/object.h"
#include "../utils/byte_view.h"
#include "../rtos/message_queue.h"
#include "../rtos/mutex.h"
#include "../driver/rf_uart.h"

namespace task {

struct Frame {
    uint8_t type;
    uint8_t cmd;
    uint16_t data_len;
    uint8_t *data;
};


class RfTask : public rtos::Thread<RfTask, 1024, osPriorityHigh1> {

public:
    static constexpr uint32_t RECV_BUF_SIZE = 512;

    void run();

    template <typename... Ts>
    utils::Error request(Frame &result, uint8_t cmd, Ts&&... ts) {
        using namespace utils;
        using namespace driver;
        AUTO_LOCK(m_mutex);
        m_res_mq.reset();
        rfUart->write(cmd, std::forward<Ts>(ts)...);
        return ((m_res_mq.poll(result, 100) == osOK) ? ec::OK : ec::RFID_CONN_TIMEOUT);
    }

    utils::Error send(Frame &result, uint8_t cmd, const utils::ByteView &bw) {
        using namespace utils;
        using namespace driver;
        AUTO_LOCK(m_mutex);
        m_res_mq.reset();
        rfUart->write_parameter(cmd, bw);
        return ((m_res_mq.poll(result, 500) == osOK) ? ec::OK : ec::RFID_CONN_TIMEOUT);
    }

private:
    void on_recv(const Frame &frame);

    bool poll();
    bool is_empty() { return m_bw.len == 0x00; }
    uint8_t take_if_not_empty();
    uint8_t take(uint8_t *dest, uint8_t len);
    void exec_once();
    bool sync(Frame &frame);
    
    uint8_t m_recv_buf[RECV_BUF_SIZE];
    uint32_t m_recv_index = 0;
    utils::ByteView m_bw;

    rtos::MessageQueue<Frame, 1> m_res_mq;
    rtos::Mutex m_mutex;
};

inline utils::Object<RfTask> rfTask;

}

#endif
